package com.yue.ssa.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yue.ssa.bean.RespBean;
import com.yue.ssa.bean.File;
import com.yue.ssa.common.Constant;
import com.yue.ssa.exception.MyException;
import com.yue.ssa.mapper.FileMapper;
import com.yue.ssa.service.FileService;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author zhengyl
 * @description
 * @date 2020-04-08 9:34
 */
@Service
@Transactional
public class FileServiceImpl extends ServiceImpl<FileMapper, com.yue.ssa.bean.File> implements FileService {


    @Value("${file.distUrl}")
    private String distUrl;
    @Value("${file.netUrl}")
    private String netUrl;

    private String FILE_SEPARATOR = System.getProperty("file.separator");
    private ExecutorService executorService = Executors.newCachedThreadPool();

    @Override
    public RespBean upload(MultipartFile multipartFile) {
        if (multipartFile == null || multipartFile.getSize() == 0L) {
            throw new MyException(Constant.FILE_INVALID);
        }
        try {
            String originalFilename = multipartFile.getOriginalFilename();
            String uuid = UUID.randomUUID().toString().toLowerCase().replace("-", "");
            String suffix = "";
            if (originalFilename.contains(".")) {
                suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            String name = uuid + suffix;
            StringBuilder sb = new StringBuilder();
            Calendar calendar = Calendar.getInstance();
            int year = calendar.get(Calendar.YEAR);
            int month = calendar.get(Calendar.MONTH) + 1;
            sb.append(distUrl);//拼接一级目录
            String path = FILE_SEPARATOR + year + FILE_SEPARATOR + month + FILE_SEPARATOR;
            sb.append(path);//拼接二级目录
            java.io.File f1 = new java.io.File(sb.toString());
            if (!f1.exists()) {//文件目录不存在则创建
                f1.mkdirs();
            }
            String pathUrl = sb.append(name).toString();//拼接成绝对路径
            String url = netUrl + path + name;
            java.io.File f2 = new java.io.File(pathUrl);
            f2.createNewFile();
            executorService.execute(() -> {
                try {
                    multipartFile.transferTo(f2);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            File file = new File();
            file.setName(originalFilename);
            file.setPath(pathUrl);
            file.setUrl(url);
            file.setCreateTime(new Date());
            this.save(file);
            return RespBean.ok(file);
        } catch (IOException e) {
            throw new MyException(e.getMessage());
        }
    }

    @Override
    public RespBean get(String id) {
        File file = this.getById(id);
        if (file == null) {
            throw new MyException(Constant.BEANID_INVALID);
        }
        return RespBean.ok(file);
    }


    @Override
    public void download(HttpServletResponse response, String id) {
        File file = this.getById(id);
        if (file == null) return;
        InputStream inputStream = null;
        try {
            inputStream = new BufferedInputStream(new FileInputStream(file.getPath()));
            response.setHeader("Content-disposition", String.format("attachment; filename=" + new String(file.getName().getBytes("gbk"), "iso8859-1")));
            IOUtils.copy(inputStream, response.getOutputStream());
            inputStream.close();
        } catch (IOException e) {
            throw new MyException(Constant.FILE_NOT_EXISTENT);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                    response.getOutputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public RespBean getFilesByRelatedId(String relatedId) {
        Map<String, Object> params = new HashMap<>();
        params.put("related_id", relatedId);
        return RespBean.ok(this.listByMap(params));
    }

    @Override
    public RespBean delete(String[] ids) {
        return RespBean.ok(this.removeByIds(Arrays.asList(ids)));
    }

    @Override
    public void batchDownload(HttpServletResponse response, String[] ids) {
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        DataOutputStream os = null;
        ZipOutputStream zipos = null;
        //设置压缩包的名字
        String downloadName = Constant.BATCH_DOWNLOAD_NAME;
        try {
            response.setHeader("Content-disposition", String.format("attachment; filename=" + new String(downloadName.getBytes("gbk"), "iso8859-1")));
            //设置压缩流：直接写入response，实现边压缩边下载
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED);//设置压缩方法

            //循环将文件写入压缩流
            //遍历文件信息（主要获取文件名/文件路径等）
            for (String id : ids) {
                if (StringUtils.isBlank(id)) continue;
                //文件路径
                File file = this.getById(id);
                if (file == null) continue;
                java.io.File file2 = new java.io.File(file.getPath());
                if (!file2.exists()) {
                    continue;
                } else {
                    //添加ZipEntry，并ZipEntry中写入文件流
                    zipos.putNextEntry(new ZipEntry(file.getName()));
                    os = new DataOutputStream(zipos);
                    FileInputStream fileInputStream = new FileInputStream(file2);
                    byte[] bytes = new byte[2048];
                    int length;
                    while ((length = fileInputStream.read(bytes)) != -1) {
                        os.write(bytes, 0, length);
                    }
                    fileInputStream.close();
                    zipos.closeEntry();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if (os != null) {
                try {
                    os.flush();
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (zipos != null) {
                try {
                    zipos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public List getInputStream(String[] paths) {
        List byteList = new ArrayList<>();
        for (String path : paths) {
            try {
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                FileInputStream in = new FileInputStream(path);
                byte[] buffer = new byte[in.available()];
                in.read(buffer);
                out.write(buffer);
                byteList.add(out.toByteArray());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return byteList;
    }
}
